package br.edu.ufc.deti.broker.execucao;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import br.edu.ufc.deti.beans.Aplicacao;
import br.edu.ufc.deti.beans.Mensagem;
import br.edu.ufc.deti.beans.PerfClusters;
import br.edu.ufc.deti.beans.Recurso;
import br.edu.ufc.deti.broker.descisao.NgcDescisao;
import br.edu.ufc.deti.broker.mapeamento.ExecucaoMapping;
import br.edu.ufc.deti.broker.mapeamento.bean.PerfClustersDecorator;
import br.edu.ufc.deti.broker.negocio.policiamento.NgcPoliciamentoRecursos;
import br.edu.ufc.deti.broker.negocio.quotas.NgcCotasUsuario;
import br.edu.ufc.deti.util.ResourceUtils;
import br.edu.ufc.deti.util.Utils;

public class NgcExecucao {

	private PerfClustersDecorator decorator = new PerfClustersDecorator(Utils.populaPerfClusters());
	private final String pathServer = "/home/antonio/workspace_helios/perfclusters";
	private final String FILE_NAME_PATH = "/application.properties";
	private PerfClusters perfClusters;

	public NgcExecucao( PerfClusters perfClusters ) {
		this.perfClusters = perfClusters;
	}

	public NgcExecucao( String xml ) {
		try {
			perfClusters = ExecucaoMapping.getInstance().unmarshalPerfClusters(xml, decorator);
		} catch (Exception e) {
			perfClusters = treatException( e, perfClusters );
		}
	}
	
	public String executaAplicacao_Recursos() {
		String 	xml = "";
		try {
			perfClusters = NgcCotasUsuario.getInstance().verificaCotaUsuario( perfClusters );
			if( perfClusters.getMensagens().size() == 0 ){
				perfClusters = new NgcDescisao( perfClusters ).ordenaRecursos();
				if( perfClusters.getMensagens().size() == 0 ){
					xml = executaAplicacao_Recurso();
				} else {
					xml = ExecucaoMapping.getInstance().marshalPerfClusters( decorator );
				}
			} else {
				xml = ExecucaoMapping.getInstance().marshalPerfClusters( decorator );
			}
		} catch (Exception e) {
			perfClusters = treatException( e, perfClusters );
		}
		return xml;
	}

	public String executaAplicacao_Recurso(){
		String xml = "";
		new NgcPoliciamentoRecursos().coletaDadosRecursos( perfClusters );
		Recurso recurso = perfClusters.getRecursos().get(0); 
		try {
			String scriptExecucaoBench = criaArquivoExecucaoAplicacao( perfClusters.getAplicacao(), recurso );
			Process proc = Runtime.getRuntime().exec( "/bin/sh "+scriptExecucaoBench );
			for (int i = 0; proc.waitFor() > 0; i++) {}
			if ( proc.waitFor() == 0 ) {
				perfClusters.getAplicacao().setResultApp("http://localhost:8081/perfclusters/resultados/results.txt");
				xml = ExecucaoMapping.getInstance().marshalPerfClusters( decorator );
			}
		} catch ( Exception e ) {
			perfClusters = treatException( e, perfClusters );
		}
		return xml;
	}

	public String criaArquivoExecucaoAplicacao( Aplicacao aplicacao, Recurso recurso ) throws IOException {
		String hostDestino = recurso.getHostRecurso();
		String userDestino = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "USER_"+hostDestino );
		String tipoRecurso = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "TYPE_"+hostDestino );
		
		File fileApp = new File( pathServer+"/scripts-apps/input.in" ); 

		String pathScript = pathServer+"/scripts-apps/script_"+aplicacao.getNome()+"_exec.sh";
		
		FileWriter fileExecApp = new FileWriter( pathScript );
		fileExecApp.write("#!/bin/sh\n");
		if ( tipoRecurso.equalsIgnoreCase("fisico") ) {
			//fileExecApp.write("scp "+aplicacao.getAbsolutePath()+" "+userDestino+"@"+hostDestino+":/home/"+userDestino+"/"+aplicacao.getName()+" \n");
			//fileExecApp.write("ssh "+userDestino+"@"+hostDestino+" 'mpicc "+aplicacao.getName()+" -o "+nomeAplicacao+" \n");
			//fileExecApp.write("ssh "+userDestino+"@"+hostDestino+" 'mpirun -n 4 ./"+nomeAplicacao+"' \n");
			//fileExecApp.write("scp "+userDestino+"@"+hostDestino+":~/"+nomeAplicacao+"_resultado.txt "+pathServer+"/WebContent/resultados/ \n");
			
			// comando  'mpiexec -np 4 /shared/bin/mpiblast -d drosoph.nt -i test.in -p blastn -o results.txt'
			fileExecApp.write("scp "+fileApp.getAbsolutePath()+" "+userDestino+"@"+hostDestino+":/home/"+userDestino+"/"+fileApp.getName()+" \n");
			fileExecApp.write("ssh "+userDestino+"@"+hostDestino+" 'mpiexec -np 4 /shared/bin/mpiblast -d "+aplicacao.getBase()+" -i "+aplicacao.getSequencia()+" -p blastn -o results.txt' exit \n");
			fileExecApp.write("scp "+userDestino+"@"+hostDestino+":~/results.txt "+pathServer+"/WebContent/resultados/ \n");
		}else if( tipoRecurso.equalsIgnoreCase("powercost") ){
			//String pathBLAST = "./opt/Bio/mpiblast/bin/mpiblast";
			fileExecApp.write("scp -P 34521 "+fileApp.getAbsolutePath()+" "+userDestino+"@"+hostDestino+":/home/"+userDestino+"/"+fileApp.getName()+" \n");
			fileExecApp.write("ssh "+userDestino+"@"+hostDestino+" -p 34521 'mpiexec -np 4 mpiblast -d "+aplicacao.getBase()+" -i "+fileApp.getName()+" -p blastn -o results.txt'\n");
			fileExecApp.write("scp -P 34521 "+userDestino+"@"+hostDestino+":~/results.txt "+pathServer+"/WebContent/resultados/ \n");
		}else if( tipoRecurso.equalsIgnoreCase("uchicago") ){ //cluster virtuais Andrea
			String pathMPI = "./mpi/mpich2-1.0.7/build_i386_fc8/bin/mpiexec";
			String pathBLAST = "./blast/mpiBLAST-1.5.0-pio/build_i386_fc8_mpich/bin/mpiblast";
			// comando  'mpiexec -np 4 /shared/bin/mpiblast -d drosoph.nt -i test.in -p blastn -o results.txt'
			fileExecApp.write("scp -o StrictHostKeyChecking=no "+fileApp.getAbsolutePath()+" "+userDestino+"@"+hostDestino+":/opt/"+fileApp.getName()+" \n");
			fileExecApp.write("ssh -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+" '\n cd /opt \n");
			fileExecApp.write("/opt/mpi/mpich2-1.0.7/build_i386_fc8/bin/mpdboot \n");
			fileExecApp.write( pathMPI+" -np 4 "+pathBLAST+" -d "+aplicacao.getBase()+" -i "+fileApp.getName()+" -p blastn -o results.txt' \n");
			fileExecApp.write("scp -o StrictHostKeyChecking=no "+userDestino+"@"+hostDestino+":/opt/results.txt "+pathServer+"/WebContent/resultados/");
		}
		fileExecApp.close();
		return pathScript;
	}
	
	public String criaArquivoPBSExecucaoAplicacao( Aplicacao aplicacao, Recurso recurso ) throws IOException {
		String hostDestino = recurso.getHostRecurso();
		String userDestino = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "USER_"+hostDestino );
		String tipoRecurso = ResourceUtils.getInstance().getProperty( FILE_NAME_PATH, "TYPE_"+hostDestino );
		
		File fileApp = new File( pathServer+"/scripts-apps/input.in" ); 
		String pathScript = pathServer+"/scripts-apps/script_"+aplicacao.getNome()+"_exec.sh";
		FileWriter fileExecApp = new FileWriter( pathScript );

		fileExecApp.write("#!/bin/sh");
		fileExecApp.write("#PBS -q paralela\n");
		fileExecApp.write("#PBS -N testjob\n");
		fileExecApp.write("#PBS -V\n");
		fileExecApp.write("#PBS -l ncpus=4\n");
		fileExecApp.write("#!/bin/sh\n");
		fileExecApp.write("cd $PBS_O_WORKDIR\n");
		fileExecApp.write("echo \"-----------------------------------------\"\n");
		fileExecApp.write("echo \"Inicio do job:\" 'date'\n");
		fileExecApp.write("echo \"Hostname: \" 'hostname'\n");
		fileExecApp.write("echo \"PWD: \" $PWD\n");
		fileExecApp.write("echo \"Arquivos:\"\n");
		fileExecApp.write("mpirun -np 4  <executável>\n");
		fileExecApp.write("echo \"Final do job:\" 'date'\n");
		fileExecApp.write("echo \"-----------------------------------------\"\n");
		fileExecApp.close();
		return pathScript;
	}

	/**
	 * Método utilizado para fazer o tratamento caso ocorra uma exceção.
	 * @param e A exceção que ocorreu.
	 * @param perfClusters PerfClusters que foi enviado pelo cliente.
	 * @return Objeto perfClusters de retorno.
	 */
	private PerfClusters treatException( Exception e, PerfClusters perfClusters ) {
		e.printStackTrace();
		if( perfClusters == null ) perfClusters = Utils.populaPerfClusters();
		perfClusters.getMensagens().add( new Mensagem( "erro", e.getMessage() ) );
		return perfClusters;
	}
}
